/**
 * 
 */
package com.jolestar.yayaweibotong.service.impl;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

import com.google.appengine.api.datastore.FetchOptions;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.datastore.Query;
import com.google.appengine.api.datastore.Query.FilterOperator;
import com.google.appengine.api.datastore.Query.SortDirection;
import com.google.appengine.api.mail.MailService;
import com.google.appengine.api.mail.MailService.Message;
import com.google.appengine.api.mail.MailServiceFactory;
import com.google.appengine.repackaged.com.google.common.collect.Lists;
import com.jolestar.yayaweibotong.ServiceType;
import com.jolestar.yayaweibotong.YaYaConstants;
import com.jolestar.yayaweibotong.YayaException;
import com.jolestar.yayaweibotong.dao.AbstractDomain;
import com.jolestar.yayaweibotong.dao.AccountDomain;
import com.jolestar.yayaweibotong.dao.DomainFactory;
import com.jolestar.yayaweibotong.dao.InviteTokenDomain;
import com.jolestar.yayaweibotong.dao.StatusDomain;
import com.jolestar.yayaweibotong.dao.UserDomain;
import com.jolestar.yayaweibotong.service.UserService;
import com.jolestar.yayaweibotong.util.YaYaUtils;

/**
 * @author jolestar@gmail.com
 * 
 */
public class UserServiceImpl implements UserService {

	private static final Logger log = Logger.getLogger(UserServiceImpl.class
			.getName());

	private MailService mailService = MailServiceFactory.getMailService();

	/**
	 * 
	 */
	public UserServiceImpl() {
	}

	public UserDomain getDefaultUser() {
		UserDomain user = this.getUser(YaYaConstants.DEFAULT_USER);
		if (user == null) {
			user = this.createUser(YaYaConstants.DEFAULT_USER, null, null);
		}
		return user;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.jolestar.yayaweibotong.service.UserService#getUsers(int, int)
	 */
	@Override
	public List<UserDomain> getUsers(int startIndex, int batchSize) {
		Query query = new Query(UserDomain.class.getName());
		Iterable<UserDomain> users = DomainFactory.getAllByQuery(query,
				FetchOptions.Builder.withOffset(startIndex).limit(batchSize));
		return Lists.newArrayList(users);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.jolestar.yayaweibotong.service.UserService#getUser(java.lang.String)
	 */
	@Override
	public UserDomain getUser(String email) {
		return DomainFactory.load(UserDomain.class, ServiceType.yaya, email);
	}

	@Override
	public AccountDomain getAccount(ServiceType serviceType, String originalId) {
		return DomainFactory.load(AccountDomain.class, serviceType, originalId);
	}

	@Override
	public AccountDomain getAccount(String keyName) {
		return DomainFactory.load(AccountDomain.class, keyName);
	}

	@Override
	public void deleteAccount(String keyName) {
		DomainFactory.delete(KeyFactory.createKey(
				AccountDomain.class.getName(), keyName));
	}

	@Override
	public boolean validateInviteToken(String inviteToken) {
		InviteTokenDomain token = this.getInviteToken(inviteToken);
		return token != null && !token.isUsed();
	}

	public InviteTokenDomain getInviteToken(String tokenStr) {
		InviteTokenDomain token = DomainFactory.load(InviteTokenDomain.class,
				ServiceType.yaya, tokenStr);
		return token;
	}
	
	@Override
	public List<InviteTokenDomain> getUsedTokens() {
		Query query = new Query(InviteTokenDomain.class.getName());
		query.addFilter(InviteTokenDomain.USED_PROPERTY, FilterOperator.EQUAL,
				true);
		return DomainFactory.getListByQuery(query);
	}

	@Override
	public List<InviteTokenDomain> getUnUsedTokens() {
		Query query = new Query(InviteTokenDomain.class.getName());
		query.addFilter(InviteTokenDomain.USED_PROPERTY, FilterOperator.EQUAL,
				false);
		return DomainFactory.getListByQuery(query);
	}

	@Override
	public void generateInviteToken(int count) {
		for (int i = 0; i < count; i++) {
			InviteTokenDomain token = new InviteTokenDomain(
					YaYaUtils.randomString(10), this.getDefaultUser());
			token.save();
		}
	}

	@Override
	public UserDomain createUser(String email, String password, String tokenStr) {
		if (password == null) {
			password = YaYaUtils.randomString(6);
		}
		log.info("create user by email:" + email);
		UserDomain user = new UserDomain(email, password);
		if (YaYaConstants.INVITE_ENABLE && tokenStr != null) {
			InviteTokenDomain token = this.getInviteToken(tokenStr);
			if (token == null) {
				throw new YayaException("邀请码无效");
			}
			token.use(user);
			token.save();
		}
		user.save();
		String loginUrl = YaYaConstants.APP_URL + "/login";
		log.info("create user success.");
		// TODO 邮件模板
		this.sendEmail(email, "您在" + YaYaConstants.APP_NAME + "注册成功", "登录邮箱:"
				+ email + "<br/>登录密码:" + password + "<br/> <a href=\""
				+ loginUrl + "\">点击此处登录</a> 或者复制地址:" + loginUrl + " 到浏览器。");
		log.info("send email success.");
		return user;
	}

	@Override
	public void sendEmail(String toEmail, String subject, String content) {
		Message message = new Message();
		message.setSender(YaYaConstants.DEFAULT_EMAIL_ACCOUNT);
		message.setTo(toEmail);
		message.setSubject(subject);
		message.setHtmlBody(content);
		try {
			this.mailService.send(message);
			log.info("send emai to:" + toEmail + ",subject:" + subject);
		} catch (IOException e) {
			throw new YayaException(e);
		}
	}

	@Override
	public void sendEmailToAdmin(String subject, String content) {
		Message message = new Message();
		message.setSender(YaYaConstants.DEFAULT_EMAIL_ACCOUNT);
		message.setSubject(subject);
		message.setTextBody(content);
		try {
			this.mailService.sendToAdmins(message);
		} catch (IOException e) {
			throw new YayaException(e);
		}
	}

	@Override
	public List<UserDomain> getNeedSyncUsers(int startIndex,int maxResults) {
		Query query = new Query(UserDomain.class.getName());
		query.addFilter(UserDomain.ACTIVITY_PROPERTY, FilterOperator.EQUAL,
				true);
		query.addFilter(UserDomain.SYNCED_PROPERTY, FilterOperator.EQUAL, false);
		return DomainFactory.getListByQuery(query,
				FetchOptions.Builder.withOffset(startIndex).limit(maxResults));
	}

	@Override
	public List<UserDomain> getActivityUsers(int startIndex, int maxResults) {
		Query query = new Query(UserDomain.class.getName());
		query.addFilter(UserDomain.ACTIVITY_PROPERTY, FilterOperator.EQUAL,
				true);
		return DomainFactory.getListByQuery(query,
				FetchOptions.Builder.withOffset(startIndex).limit(maxResults));
	}

	@Override
	public List<StatusDomain> getUnSyncedStatuses(AccountDomain account,
			int maxResults) {
		Query query = new Query(StatusDomain.class.getName());
		query.addFilter(StatusDomain.IS_SYNCED_PROPERTY, FilterOperator.EQUAL,
				false);
		query.addFilter(StatusDomain.ACCOUNT_ID_PROPERTY, FilterOperator.EQUAL,
				account.getOriginalId());
		query.addSort(StatusDomain.CREATED_AT_PROPERTY, SortDirection.ASCENDING);
		return DomainFactory.getListByQuery(query,
				FetchOptions.Builder.withLimit(maxResults));
	}

	@Override
	public List<StatusDomain> getLatestOriginalStatus(int maxResults,
			String sinceKeyName) {
		Query query = new Query(StatusDomain.class.getName());
		query.addFilter(StatusDomain.IS_ORIGINAL_STATUS_PROPERTY,
				FilterOperator.EQUAL, true);
		query.addSort(StatusDomain.CREATED_AT_PROPERTY,
				SortDirection.DESCENDING);
		List<StatusDomain> statuses = DomainFactory.getListByQuery(query,
				FetchOptions.Builder.withLimit(maxResults));
		if (sinceKeyName == null) {
			return statuses;
		} else {
			List<StatusDomain> filterResults = new ArrayList<StatusDomain>();
			for (StatusDomain status : statuses) {
				if (!status.getKeyName().equals(sinceKeyName)) {
					filterResults.add(status);
				} else {
					break;
				}
			}
			return filterResults;
		}
	}

	@Override
	public boolean exists(Class<? extends AbstractDomain> domainClass,
			ServiceType serviceType, String originalId) {
		return DomainFactory.contains(domainClass, serviceType, originalId);
	}

	@Override
	public StatusDomain getStatus(String keyName) {
		return DomainFactory.load(StatusDomain.class, keyName);
	}

}
